package cn.qicaiwang.open.qxyApi.util;

import cn.qicaiwang.open.qxyApi.config.QxyApiProperties;
import cn.qicaiwang.open.qxyApi.entity.AccessTokenEntity;
import cn.qicaiwang.open.qxyApi.entity.ApiInvokeLog;
import cn.qicaiwang.open.qxyApi.mapper.AccessTokenMapper;
import cn.qicaiwang.open.qxyApi.server.ApiInvokeLogService;
import com.alibaba.fastjson.JSONObject;
import lombok.var;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ReactiveRedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.sql.rowset.BaseRowSet;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.URI;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

@Service
public class ApiServer {

    @Autowired
    private ApiInvokeLogService apiInvokeLogService;

    private final QxyApiProperties properties;
    private final RedisTemplate<String, Object> redisTemplate;

    private static final String QXY_ACCESS_TOKEN_KEY = "qxy:access_token";
    private static final long TOKEN_EXPIRE_TIME = 7 * 24 * 60 * 60;

    @Autowired
    private AccessTokenMapper accessTokenMapper;

    private static final long TOKEN_EXPIRE_SECONDS = TimeUnit.HOURS.toSeconds(24);

    // 使用构造器注入
    @Autowired
    public ApiServer(QxyApiProperties properties, RedisTemplate<String, Object> redisTemplate) {
        this.properties = properties;
        this.redisTemplate = redisTemplate;
    }

    public JSONObject callApi(String apiPath, String requestBody, String apiName) throws Exception {
        long startTime = System.currentTimeMillis();
        boolean success = false;
        String errorCode = null;
        String errorMessage = null;
        JSONObject result = null;
        Throwable exception = null;
        String thirdPartyIp = null; // 新增：用于存储第三方API的IP地址

        try {
            // 1. 获取access_token
            JSONObject tokenInfo = getAccessToken();
            String accessToken = tokenInfo.getString("token");

            // 2. 构建完整URL
            String apiUrl = properties.getUrl() + apiPath;

            // 新增：解析第三方API的IP地址
            try {
                URI uri = new URI(apiUrl);
                String host = uri.getHost();
                if (host != null) {
                    InetAddress address = InetAddress.getByName(host);
                    thirdPartyIp = address.getHostAddress();
                }
            } catch (Exception e) {
                thirdPartyIp = "unknown";
            }

            // 3. 生成请求时间戳
            String reqDate = String.valueOf(System.currentTimeMillis());

            // 4. 使用传入的请求体
            JSONObject requestJson = JSONObject.parseObject(requestBody);
            String requestBodyStr = requestJson.toJSONString();

            // 5. 生成签名
            String reqSign = SignUtil.generateSign(
                    properties.getAppKey(),
                    properties.getAppSecret(),
                    accessToken,
                    reqDate,
                    requestBodyStr
            );

            // 6. 准备请求头
            Map<String, String> headers = new HashMap<>();
            headers.put("access_token", accessToken);
            headers.put("req_date", reqDate);
            headers.put("req_sign", reqSign);
            headers.put("Content-Type", "application/json;charset=UTF-8");

            // 7. 调用第三方API
            String response = sendPostRequest(apiUrl, headers, requestBodyStr);

            // 8. 解析响应
            result = JSONObject.parseObject(response);
            success = true;

            return result;
        } catch (Exception e) {
            exception = e;
            errorCode = "API_CALL_FAILED";
            errorMessage = e.getMessage();
            throw e;
        } finally {
            try {
                // 记录日志
                ApiInvokeLog log = apiInvokeLogService.logApiInvoke(
                        apiName,
                        apiPath,
                        "POST",
                        null,
                        null, // 无URL参数
                        requestBody,
                        result != null ? result.toJSONString() : null,
                        success,
                        errorCode,
                        errorMessage,
                        exception,
                        thirdPartyIp

                );


            } catch (Exception e) {

            }
        }
    }

    private static String sendPostRequest(String url, Map<String, String> headers, String body) throws Exception {
        HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8");

        // 设置请求头
        headers.forEach(conn::setRequestProperty);

        conn.setDoOutput(true);
        try (DataOutputStream wr = new DataOutputStream(conn.getOutputStream())) {
            wr.write(body.getBytes(StandardCharsets.UTF_8));
        }

        return readResponse(conn);
    }


    // 保留原有的readResponse方法
    private static String readResponse(HttpURLConnection conn) throws IOException {
        try (BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()))) {
            String inputLine;
            StringBuilder content = new StringBuilder();
            while ((inputLine = in.readLine()) != null) {
                content.append(inputLine);
            }
            return content.toString();
        }
    }

    public JSONObject getAccessToken() throws Exception {
        // 先从数据库获取
        AccessTokenEntity tokenEntity = accessTokenMapper.findLatestToken();
        if (tokenEntity != null && !isTokenExpired(tokenEntity.getExpiresAt())) {
            JSONObject jsonToken = new JSONObject();
            jsonToken.put("token", tokenEntity.getToken());
            return jsonToken;
        }

        // 数据库中没有或已过期则刷新 token
        return refreshAccessTokenAndStoreInDB();
    }

    private boolean isTokenExpired(LocalDateTime expiresAt) {
        return LocalDateTime.now().isAfter(expiresAt);
    }

    private JSONObject refreshAccessTokenAndStoreInDB() throws Exception {
        // 模拟 API 调用获取新的 token
        String appKey = properties.getAppKey();
        String url = properties.getUrl();
        String appSecret = properties.getAppSecret();
        String tokenUrl = url + "/v2/public/oauth2/login";
        String body = "{\"grant_type\":\"client_credentials\",\"client_appkey\":\"" + appKey + "\",\"client_secret\":\"" + md5(appSecret) + "\"}";

        HttpURLConnection conn = (HttpURLConnection) new URL(tokenUrl).openConnection();
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
        conn.setDoOutput(true);

        try (DataOutputStream wr = new DataOutputStream(conn.getOutputStream())) {
            wr.write(body.getBytes(StandardCharsets.UTF_8));
        }

        String response = readResponse(conn);
        System.out.println("示例获取token结果:" + response);
        JSONObject resultJson = JSONObject.parseObject(response);
        String accessTokenValue = resultJson.getJSONObject("data").getString("access_token");

        LocalDateTime expiresAt = LocalDateTime.now().plusSeconds(TOKEN_EXPIRE_SECONDS);
        accessTokenMapper.insertToken(accessTokenValue, expiresAt);

        JSONObject jsonToken = new JSONObject();
        jsonToken.put("token", accessTokenValue);
        return jsonToken;
    }





    private static String md5(String input) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] digest = md.digest(input.getBytes(StandardCharsets.UTF_8));
        return bytesToHex(digest);
    }

    private static String bytesToHex(byte[] bytes) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : bytes) {
            String hex = Integer.toHexString(0xff & b);
            if (hex.length() == 1) hexString.append('0');
            hexString.append(hex);
        }
        return hexString.toString();
    }
}